﻿#region Copyright (c) 2010 R. Uittenbosch
/*
* Copyright (C) 2010 R. Uittenbosch
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
* associated documentation files (the "Software"), to deal in the Software without restriction, including 
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the 
* following conditions:
* 
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 
* EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#endregion

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using OAuth.Net.Mobile.Consumer;
using System.Xml.Serialization;
using System.IO;
using System.Collections.ObjectModel;
using OAuth.Net.Mobile.Common;
using LinkedService.Mobile.Utility;
using System.Globalization;
using Microsoft.Practices.ServiceLocation;
using LinkedService.Mobile.ServiceEntities;

namespace LinkedService.Mobile
{
  #region _
  public static class _
  {
    private static string δ(this string __, int _) { return __.Substring(_, 2); }
    public static string α(this string _) { string __ = default(string); for (int ___ = 0; ___ < _.Length; ___++) __ = __ + ((char)int.Parse(_.δ(___++), (NumberStyles)0x203)); return __; }
  }
  #endregion

  #region UriBuilderExtension
  /// <summary>
  /// Extensions on the UriBuilder class
  /// </summary>
  public static class UriBuilderExtensions
  {

    public static void AppendPathParameters(this UriBuilder location, List<string> parameters)
    {
      if (parameters != null)
        location.Path = string.Format("{0}:({1})", location.Path, string.Join(",", parameters.ToArray()));
    }

    public static void AppendQueryParameters(this UriBuilder location, IEnumerable<KeyValuePair<string, string>> parameters)
    {
      StringBuilder sb = new StringBuilder();

      if (string.IsNullOrEmpty(location.Query) == false)
        sb.Append(location.Query.Substring(1));

      foreach (KeyValuePair<string, string> pair in parameters)
      {
        sb.Append(string.Format("{0}={1}&", HttpUtility.UrlEncode(pair.Key), HttpUtility.UrlEncode(pair.Value)));
      }
      location.Query = sb.ToString();
    }
  }

  #endregion

  #region CollectionExtensions
  /// <summary>
  /// Extensions to the collection class
  /// </summary>
  public static class CollectionExtensions
  {
    public static void AddNonEmpty(this Collection<KeyValuePair<string, string>> collection, string key, string val)
    {
      if (!string.IsNullOrEmpty(val))
        collection.Add(new KeyValuePair<string, string>(key, val));
    }
    public static void AddNonEmpty(this Collection<KeyValuePair<string, string>> collection, string key, int val)
    {
      if (val >= 0)
        collection.Add(new KeyValuePair<string, string>(key, val.ToString()));
    }
  }

  #endregion

  #region ObjectExtensions

  /// <summary>
  /// Extensions to any object so objectserialization is easy
  /// </summary>
  public static class ObjectExtensions
  {
    /// <summary>
    /// Convert to the object to an UTF8ByteArray
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static byte[] ToUTF8ByteArray(this string data)
    {
      return new UTF8Encoding().GetBytes(data);
    }

    /// <summary>
    /// Serialize an object to byte[]
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static byte[] SerializeToXmlByte<T>(this T obj)
    {
      if (obj as IXmlSerializable == null) throw new NotSupportedException("Object of type " + typeof(T) + "does not implement IXmlSerializable.");
      return Encoding.UTF8.GetBytes(obj.SerializeToXml());
    }

    /// <summary>
    /// Serialize an object to string
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static string SerializeToXml<T>(this T obj) 
    {
      if (obj as IXmlSerializable == null) throw new NotSupportedException("Object of type " + typeof(T) + "does not implement IXmlSerializable.");
      XmlSerializerNamespaces xmlSerializerNamespaces = new XmlSerializerNamespaces();
      xmlSerializerNamespaces.Add(string.Empty, string.Empty);

      var xmlSerializer = new XmlSerializer(typeof(T));
      var memoryStream = new MemoryStream();
      xmlSerializer.Serialize(memoryStream, obj, xmlSerializerNamespaces);
      return Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
    }    

    /// <summary>
    /// Dump a string to file
    /// </summary>
    /// <param name="obj"></param>
    public static void Dump(this string obj)
    {
      string path = ServiceLocator.Current.GetInstance<IConfiguration>().GetItem<string>("DumpPath") + @"\Log";
      if (!Directory.Exists(path))
        Directory.CreateDirectory(path);
      string filename = path + @"\" +  UnixTime.ToUnixTime(DateTime.Now).ToString() + ".xml";
      using (StreamWriter w = new StreamWriter(filename))
      {
        w.Write(obj);
        w.Close();
      }
    }

    /// <summary>
    /// Save an object to the Storage Card
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    public static void Save<T>(this T obj)
    {
      if (obj as IXmlSerializable == null) throw new NotSupportedException("Object of type " + typeof(T) + "does not implement IXmlSerializable.");
      string path = ServiceLocator.Current.GetInstance<IConfiguration>().GetItem<string>("DumpPath");
      if (!Directory.Exists(path + @"\Log"))
        Directory.CreateDirectory(path + @"\Log");
      string filename = path + @"\Saved" + UnixTime.ToUnixTime(DateTime.Now).ToString() + ".xml";
      using (StreamWriter w = new StreamWriter(filename))
      {
        w.Write(obj.SerializeToXml());
        w.Close();
      }      
    }

    /// <summary>
    /// Load an object from file
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="filename"></param>
    /// <returns></returns>
    public static T Load<T>(this string filename) 
    {
      StreamReader r = new StreamReader(filename);
      T res = DeserializeXml<T>(r.ReadToEnd());
      r.Close();
      return res;
    }

    /// <summary>
    /// Deserialize an object to an instance
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="data"></param>
    /// <returns></returns>
    public static T DeserializeXml<T>(this string data) 
    {
      if (string.IsNullOrEmpty(data))
      {
        return default(T);
      }

      var xs = new XmlSerializer(typeof(T));
      var memoryStream = new MemoryStream(data.ToUTF8ByteArray());

      try
      {
        return (T)xs.Deserialize(memoryStream);
      }
      catch (InvalidOperationException e)
      {
        throw new LinkedInException("Could not deserialize the data.", e);
      }
    }
  }
  #endregion

  #region IntExtensions
  public static class IntExtensions
  {
    /// <summary>
    /// Try to parse a string to an integer
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static bool TryParse(this string data, out int val)
    {
      val = 0;
      return data.TryParse(0, out val);
    }

    /// <summary>
    /// Try to parse a string to an integer, default value = def
    /// </summary>
    /// <param name="data"></param>
    /// <param name="def"></param>
    /// <param name="val"></param>
    /// <returns></returns>
    public static bool TryParse(this string data, int def, out int val)
    {
      val = def;
      try
      {
        val = int.Parse(data);
        return true;
      }
      catch
      {
        return false;
      }
    }
  }
  #endregion


  public static class EnumExtensions
  {
    public static bool Contains(this object val, object contains)
    {
      return (((int)val & (int)contains) == (int)contains);
    }

    public static string Description(this object val)
    {
      DescriptionAttribute[] attributes = (DescriptionAttribute[])val.GetType().GetField(val.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
      return attributes.Length > 0 ? attributes[0].Description : string.Empty;
    }
  }

}
